<?php
/**
 * This class represents a resultset of a user query.
 * It is, at it's core, a collection of ForageDocument objects.
 *
 * @author Rob Young <rob@roryoung.co.uk>
 * @package forage.query
 */
class ForageResponse implements ArrayAccess, Iterator
{
  /**
   * Total number of documents in the response
   *
   * @var int
   */
  private $total;
  
  /**
   * The documents in this response
   *
   * @var array
   */
  private $documents;

  /**
   * Current document
   *
   * @var int
   */
  private $current;

  /**
   * Registered ForageResponseBehaviour objects
   *
   * @var array
   */
  private $behaviours;

  /**
   * Raw response from the engine
   *
   * @var mixed
   */
  private $raw;
  
  /**
   * Class constructor
   */
  public function __construct()
  {
    $this->current   = 0;
    $this->documents = array();
    $this->behaviours  = new ForageResponseBehaviourHandler();
  }

  /**
   * Pass method calls onto the behaviour handler
   * 
   * @param string $method
   * @param array $args
   * @return mixed
   */
  public function __call($method, $args)
  {
    return $this->behaviours->__call($method, $args);
  }

  
  /**
   * Magic accessor
   *
   * @param string $name
   * @return mixed
   */
  public function __get($name)
  {
    switch ($name) {
    case 'total':
      return $this->total;
    case 'raw_response':
      return $this->raw;
    default:
      return $this->behaviours->__get($name);
    }
  }

  /**
   * Set the total number of documents in the resultset.
   *
   * @param int $total
   */
  public function setTotal($total)
  {
    $this->total = $total;
  }

  /**
   * Mutator for the raw Solr response
   *
   * @param string $raw
   */
  public function setRawResponse($raw)
  {
    $this->raw = $raw;
  }

  /**
   * Check if a document exists at the given offset.
   *
   * @param int $key
   * @return boolean
   */
  public function offsetExists($key)
  {
    return isset($this->documents[$key]);
  }

  /**
   * Return the document at a given offset.
   * 
   * @param int $key
   * @return ForageDocument
   */
  public function offsetGet($key)
  {
    return $this->offsetExists($key) ? $this->documents[$key] : null;
  }

  /**
   * Append a ForageDocument to the end of the result set.
   *
   * @throws InvalidArgumentException
   * @param int $key must be null, ForageDocuments can only be appended
   * @param ForageDocument $document
   */
  public function offsetSet($key, $document)
  {
    if ($key!==null) {
      throw new InvalidArgumentException('Can only append documents');
    }
    if (!($document instanceof ForageDocument)) {
      throw new InvalidArgumentException('Can only append documents');
    }
    $this->documents[] = $document;
  }

  /**
   * ArrayAccess method which is not implemented
   *
   * @throws BadMethodCallException
   */
  public function offsetUnset($key)
  {
    throw new BadMethodCallException("cannot remove documents");
  }

  /**
   * Iterator method.
   * Return the current ForageDocument.
   *
   * @return ForageDocument
   */
  public function current()
  {
    return $this->documents[$this->current];
  }

  /**
   * Iterator method.
   * Move the internal point on by one.
   */
  public function next()
  {
    $this->current++;
  }

  /**
   * Iterator method.
   * Get the current key
   *
   * @return int
   */
  public function key()
  {
    return $this->current;
  }

  /**
   * Iterator method.
   * Check if there is a ForageDocument at the current position.
   *
   * @return boolean
   */
  public function valid()
  {
    return $this->offsetExists($this->current);
  }

  /**
   * Iterator method.
   * Reset the iterator.
   */
  public function rewind()
  {
    $this->current=0;
  }
}
